using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;

namespace PeDALS.Tools.AZ.PSTArchive
{
    public static class Utilities
    {
        #region GetPluginFileList

        /// <summary>
        /// Gets a list of files within the specified folder that contains Plugins.
        /// </summary>
        /// <param name="folder">The folder in which you want to get a plug-in list.</param>
        /// <returns>A List of files that contain valid ITaskPlugin's</returns>
        public static List<FileInfo> GetPluginFileList(string strFolder)
        {
            #region Variables

            List<FileInfo> lfiPlugs = new List<FileInfo>();

            #endregion Variables

            #region Data Validation

            // Check to make sure the folder exists
            if (Directory.Exists(strFolder) == false)
            {
                return lfiPlugs;
            }

            #endregion Data Validation

            foreach (string strFilename in Directory.GetFiles(strFolder))
            {
                if (FileContainsPlugins(strFilename) == true)
                {
                    lfiPlugs.Add(new FileInfo(strFilename));
                }
            }

            return lfiPlugs;
        }

        #endregion GetPluginFileList

        #region FileContainsPlugins

        /// <summary>
        /// Returns a boolean to indicate if the specfied filename contains plugin
        /// </summary>
        /// <param name="filename">The file name to check for plugins</param>
        /// <returns>A true if the file has at least one plugin, otherwise false.</returns>
        public static bool FileContainsPlugins(string strFilename)
        {
            #region Variables

            List<string> lstrPlugs = new List<string>();

            #endregion Variables

            #region Data Validation

            // Check to see if the file exist
            if (!File.Exists(strFilename))
            {
                return false;
            }

            #endregion Data Validation

            // Get a list of plugins from the file
            lstrPlugs = GetPlugins(strFilename);

            return (lstrPlugs.Count != 0);
        }

        #endregion FileContainsPlugins

        #region GetPlugins

        /// <summary>
        /// Gets a List of <see cref="TaskPluginInterface.ITaskPlugin"/> from the specified filename.
        /// </summary>
        /// <param name="filename">A file to load the Plugins from</param>
        /// <returns>A list of <see cref="TaskPluginInterface.ITaskPlugin">Plugins </see></returns>
        public static List<string> GetPlugins(string strFilename)
        {
            #region Variables

            Assembly aAssembly;
            List<string> lstrPlugs = new List<string>();

            #endregion Variables

            #region Data Validation

            // Check to see if the file exist
            if (!File.Exists(strFilename))
            {
                return lstrPlugs;
            }

            #endregion DataValidation

            try
            {
                aAssembly = Assembly.LoadFile(strFilename);

                // Loop through all of the type
                foreach (Type tType in aAssembly.GetTypes())
                {
                    Type[] taInterfaces = tType.GetInterfaces();
                    foreach (Type tInterface in taInterfaces)
                    {
                        if (tInterface.Name == typeof(iPlug).Name)
                        {
                            // This type/class is of type TaskPluginInterface.ITaskPlugin
                            // so we shall return it
                            lstrPlugs.Add(tType.FullName);
                        }
                    }
                }
            }
            catch (BadImageFormatException ex)
            {
                // This one we can ignore (most likely the configuration file)
            }
            catch
            {
                throw;
            }

            // Cleanup
            aAssembly = null;

            return lstrPlugs;
        }

        #endregion GetPlugins

        #region GetPlugin

        /// <summary>
        /// Returns a <see cref="ITaskPlugin" />
        /// </summary>
        /// <param name="filename">The filename that contains the Plugin</param>
        /// <param name="className">The class name to load</param>
        /// <returns>
        /// A Type that is inherited from <see cref="TaskPluginInterface.ITaskPlugin"/>, 
        /// if available, otherwise null.
        /// </returns>
        public static iPlug GetPlugin(string strFilename, string strPlug)
        {
            #region Data Validation

            // Check to see if the file exist
            if (!File.Exists(strFilename))
            {
                return null;
            }

            #endregion DataValidation

            try
            {
                System.Runtime.Remoting.ObjectHandle ohHandle = Activator.CreateInstanceFrom(strFilename, strPlug);
                return (iPlug) ohHandle.Unwrap();
            }
            catch (BadImageFormatException ex)
            {
                // This one we can ignore (most likely the configuration file)
            }
            catch
            {
                throw;
            }

            return null;

        }

        #endregion GetPlugin

        #region GetPluginFolder
        /// <summary>
        /// Returns a fully qualified path to the plug-in directory based on the folder name passed.
        /// </summary>
        /// <param name="folderName">The folder name to try and use as the plug-in folder</param>
        /// <returns>A fully qualified path to the plug-in folder.</returns>
        /// <remarks>First checks to see if the path specified exists, if so returns it.<br></br>
        /// Second, it try to see if the path is relative, if so returns it.<br></br>
        /// Third, it tries to create the directory, if successful it creates and returns the directory.<br></br>
        /// <b>null</b> is returned if all three fail.
        /// </remarks>
        /// 
        public static string GetPluginFolder(string strFolderName)
        {
            #region Variables

            string strNewFolderName;

            #endregion Variables

            // First check to see if the folder passed exists
            if (Directory.Exists(strFolderName))
            {
                strNewFolderName = Path.GetFullPath(strFolderName);
                return strNewFolderName;
            }

            // If it does not exist assume the folder specified is a sub folder of the current
            // directory.
            strNewFolderName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, strFolderName);
            if (Directory.Exists(strNewFolderName))
            {
                return strNewFolderName;
            }

            // if still does not exist try to create it.
            try
            {
                Directory.CreateDirectory(strNewFolderName);
                return strNewFolderName;
            }
            catch
            {
                return null;
            }
        }

        #endregion GetPluginFolder
    }
}
